import com.sun.syndication.io.SyndFeedInput
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.GetMethod;
import org.codehaus.groovy.grails.validation.routines.UrlValidator;

class FetchService {
    UrlValidator urlValidator = new UrlValidator()

    /** 
     * fetch content of given url
     */
    def fetch(String url) {
        def result = parseHtml(url)
        def content
        Node html
        def title
        def feeds

        println result

        if (result) {
            content = result.content
            html = result.html
            if (html) {
                title = html.HEAD.TITLE.text()
                feeds = HtmlUtils.extractFeedLink(html)
            }
        }
        [ 
            url: url,
            html: html,
            title: title,
            feeds: feeds,
            content: content
        ]
    }

    def fetchFeeds(String url) {
        parseFeed(url).feeds
    }
    
    def fetchContent(String url) {
        def headers
        def result

        if (urlValidator.isValid(url)) {
            headers = [:]
            result = [headers: headers]

            GetMethod method = new GetMethod(url)
            def client = new HttpClient()
            client.executeMethod(method)
            method.responseHeaders.each {header ->
                headers[header.name] = header.value
            }

            def charset = method.getResponseCharSet()
            def bytes = method.getResponseBody()
            result.rawData = new String(bytes, charset)
            if ((headers['Content-Type'] =~ /charset/).size() == 0) {
                def tmp = detectEncoding(result.rawData)
                if (tmp) {
                    println("detect html encoding = ${tmp}")
                    headers.charset = tmp
                    result.rawData = new String(bytes, tmp)
                }
            } else {
                headers.charset = charset
            }
        } else {
          println "invalid url ${url}"
        }
        return result
    }

    def parseHtml(String url) {
        def content = fetchContent(url)
        Node html
        if (content) {
            def parser = new org.cyberneko.html.parsers.SAXParser()
            parser.setFeature("http://xml.org/sax/features/namespaces", false)
            html = new XmlParser(parser).parseText(content.rawData)
        }
        [html: html, content: content]
    }

    def parseFeed(String url) {
        def content = fetchContent(url)
        def feeds
        if (content) {
            def input = new SyndFeedInput()
            feeds = input.build(new java.io.StringReader(content.rawData));
        }
        [feeds: feeds, content: content]
    }

    def detectEncoding(rawData) {
	def m = rawData =~ /<(meta|META)\s+(http-equiv|HTTP-EQUIV).*; charset=(.*)">/
        if (m) {
          return m[0][-1]
        }
        m = rawData =~ /<\?xml.*encoding="(.*)"/
        if (m) {
          return m[0][1]
        }
        
        return null
    }

}
